/*

  Copyright (C) 2000, 2001 Silicon Graphics, Inc.  All Rights Reserved.

  This program is free software; you can redistribute it and/or modify it
  under the terms of version 2 of the GNU General Public License as
  published by the Free Software Foundation.

  This program is distributed in the hope that it would be useful, but
  WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  

  Further, this software is distributed without any warranty that it is
  free of the rightful claim of any third person regarding infringement 
  or the like.  Any license provided herein, whether implied or 
  otherwise, applies only to this software file.  Patent licenses, if 
  any, provided herein do not apply to combinations of this program with 
  other software, or any other product whatsoever.  

  You should have received a copy of the GNU General Public License along
  with this program; if not, write the Free Software Foundation, Inc., 59
  Temple Place - Suite 330, Boston MA 02111-1307, USA.

  Contact information:  Silicon Graphics, Inc., 1600 Amphitheatre Pky,
  Mountain View, CA 94043, or:

  http://www.sgi.com

  For further information regarding this notice, see:

  http://oss.sgi.com/projects/GenInfo/NoticeExplan

*/


/* -*-Mode: c++;-*- (Tell emacs to use c++ mode) */

#ifndef be_symtab_INCLUDED
#define be_symtab_INCLUDED

#ifndef cmplr_segmented_array_INCLUDED
#include "cmplr_segmented_array.h"
#endif // cmplr_segmented_array_INCLUDED

#ifndef symtab_INCLUDED
#include "symtab.h"
#endif // symtab_INCLUDED

#ifndef wn_INCLUDED
#include "wn.h"
#endif // wn_INCLUDED

#ifndef targ_sim_INCLUDED
#include "targ_sim.h"
#endif /* targ_sim_INCLUDED */

typedef mUINT32 BE_ST_IDX;

// Definitions for BE_ST::flags

const UINT32 BE_ST_ADDR_USED_LOCALLY = 0x00000001; // Address of item is taken somewhere
const UINT32 BE_ST_ADDR_PASSED       = 0x00000002; // Address of item is passed by ref
const UINT32 BE_ST_W2FC_REFERENCED   = 0x00000004; // whirl2{f,c} sees reference to ST
const UINT32 BE_ST_UNKNOWN_CONST     = 0x00000008; // Const, with unknown value
                                                   // (Generated by LNO)
// BE_ST_ADDR_ADDR_* bits are valid only if this is set
const UINT32 BE_ST_PU_HAS_VALID_ADDR_FLAGS = 0x00000010;

// ST_ADDR_* bits are no longer valid and need to be recomputed
const UINT32 BE_ST_PU_NEEDS_ADDR_FLAG_ADJUST = 0x00000020;


// Back-end-specific information about each symtab entry

class BE_ST {
  mUINT32 flags;
  void *io_auxst;

public:
  BE_ST(void) : flags(0),io_auxst(NULL) { }
  BOOL Is_set(UINT32 f) const		{ return flags & f; }
  void Set_flag(UINT32 f)               { flags |= f; }
  void Clear_flag(UINT32 f)             { flags &= ~f; }
  void Set_io_auxst(void *v) 		{ io_auxst = v; }
  void * Io_auxst(void)			{ return io_auxst; }
};

typedef RELATED_SEGMENTED_ARRAY<BE_ST> BE_ST_TAB;

struct BE_SCOPE {
  BE_ST_TAB *be_st_tab;
};

struct BE_SCOPE_TAB_BE_ST_TAB_ACCESS {
  BE_SCOPE_TAB_BE_ST_TAB_ACCESS(void) { }

  BE_ST_TAB *operator()(BE_SCOPE **be_scope_tab, SYMTAB_IDX level)
    { return (*be_scope_tab)[level].be_st_tab; }
};

extern BE_SCOPE *Be_scope_tab;

typedef TABLE_INDEXED_BY_LEVEL8_AND_INDEX24<BE_ST, ST_IDX, SYMTAB_IDX,
					    BE_SCOPE *, &Be_scope_tab,
					    BE_SCOPE_TAB_BE_ST_TAB_ACCESS>
	BE_SYMBOL_TABLE;

extern BE_SYMBOL_TABLE	Be_symbol_table;

inline BOOL
BE_ST_addr_used_locally(const ST_IDX idx)
{
  return Be_symbol_table[idx].Is_set(BE_ST_ADDR_USED_LOCALLY);
}

inline BOOL
BE_ST_addr_used_locally(const BE_ST *const be_st)
{
  return be_st->Is_set(BE_ST_ADDR_USED_LOCALLY);
}

inline BOOL
BE_ST_addr_used_locally(const ST *const st)
{
  return Be_symbol_table[ST_st_idx(st)].Is_set(BE_ST_ADDR_USED_LOCALLY);
}

inline void
Set_BE_ST_addr_used_locally(const ST_IDX idx)
{
  Be_symbol_table[idx].Set_flag(BE_ST_ADDR_USED_LOCALLY);
}

inline void
Set_BE_ST_addr_used_locally(BE_ST *const be_st)
{
  be_st->Set_flag(BE_ST_ADDR_USED_LOCALLY);
}

inline void
Set_BE_ST_addr_used_locally(const ST *const st)
{
  Be_symbol_table[ST_st_idx(st)].Set_flag(BE_ST_ADDR_USED_LOCALLY);
}

inline void
Clear_BE_ST_addr_used_locally(const ST_IDX idx)
{
  Be_symbol_table[idx].Clear_flag(BE_ST_ADDR_USED_LOCALLY);
}

inline void
Clear_BE_ST_addr_used_locally(BE_ST *const be_st)
{
  be_st->Clear_flag(BE_ST_ADDR_USED_LOCALLY);
}

inline void
Clear_BE_ST_addr_used_locally(const ST *const st)
{
  Be_symbol_table[ST_st_idx(st)].Clear_flag(BE_ST_ADDR_USED_LOCALLY);
}

inline void
BE_ST_set_io_auxst(const ST_IDX idx, void *v)
{
  Be_symbol_table[idx].Set_io_auxst(v);
}

inline void *
BE_ST_io_auxst(const ST_IDX idx)
{
  return Be_symbol_table[idx].Io_auxst();
}


inline BOOL
BE_ST_addr_passed(const ST_IDX idx)
{
  return Be_symbol_table[idx].Is_set(BE_ST_ADDR_PASSED);
}

inline BOOL
BE_ST_addr_passed(const BE_ST *const be_st)
{
  return be_st->Is_set(BE_ST_ADDR_PASSED);
}

inline BOOL
BE_ST_addr_passed(const ST *const st)
{
  return Be_symbol_table[ST_st_idx(st)].Is_set(BE_ST_ADDR_PASSED);
}

inline void
Set_BE_ST_addr_passed(const ST_IDX idx)
{
  Be_symbol_table[idx].Set_flag(BE_ST_ADDR_PASSED);
}

inline void
Set_BE_ST_addr_passed(BE_ST *const be_st)
{
  be_st->Set_flag(BE_ST_ADDR_PASSED);
}

inline void
Set_BE_ST_addr_passed(const ST *const st)
{
  Be_symbol_table[ST_st_idx(st)].Set_flag(BE_ST_ADDR_PASSED);
}

inline void
Clear_BE_ST_addr_passed(const ST_IDX idx)
{
  Be_symbol_table[idx].Clear_flag(BE_ST_ADDR_PASSED);
}

inline void
Clear_BE_ST_addr_passed(BE_ST *const be_st)
{
  be_st->Clear_flag(BE_ST_ADDR_PASSED);
}

inline void
Clear_BE_ST_addr_passed(const ST *const st)
{
  Be_symbol_table[ST_st_idx(st)].Clear_flag(BE_ST_ADDR_PASSED);
}


inline BOOL
BE_ST_w2fc_referenced(const ST_IDX idx)
{
  return Be_symbol_table[idx].Is_set(BE_ST_W2FC_REFERENCED);
}

inline BOOL
BE_ST_w2fc_referenced(const BE_ST *const be_st)
{
  return be_st->Is_set(BE_ST_W2FC_REFERENCED);
}

inline BOOL
BE_ST_w2fc_referenced(const ST *const st)
{
  return Be_symbol_table[ST_st_idx(st)].Is_set(BE_ST_W2FC_REFERENCED);
}

inline void
Set_BE_ST_w2fc_referenced(const ST_IDX idx)
{
  Be_symbol_table[idx].Set_flag(BE_ST_W2FC_REFERENCED);
}

inline void
Set_BE_ST_w2fc_referenced(BE_ST *const be_st)
{
  be_st->Set_flag(BE_ST_W2FC_REFERENCED);
}

inline void
Set_BE_ST_w2fc_referenced(const ST *const st)
{
  Be_symbol_table[ST_st_idx(st)].Set_flag(BE_ST_W2FC_REFERENCED);
}

inline void
Clear_BE_ST_w2fc_referenced(BE_ST *const be_st)
{
  be_st->Clear_flag(BE_ST_W2FC_REFERENCED);
}

inline void
Clear_BE_ST_w2fc_referenced(const ST *const st)
{
  Be_symbol_table[ST_st_idx(st)].Clear_flag(BE_ST_W2FC_REFERENCED);
}

inline void
Clear_BE_ST_w2fc_referenced(const ST_IDX idx)
{
  Be_symbol_table[idx].Clear_flag(BE_ST_W2FC_REFERENCED);
}


inline BOOL
BE_ST_unknown_const(const ST_IDX idx)
{
  return Be_symbol_table[idx].Is_set(BE_ST_UNKNOWN_CONST);
}

inline BOOL
BE_ST_unknown_const(const BE_ST *const be_st)
{
  return be_st->Is_set(BE_ST_UNKNOWN_CONST);
}

inline BOOL
BE_ST_unknown_const(const ST *const st)
{
  return Be_symbol_table[ST_st_idx(st)].Is_set(BE_ST_UNKNOWN_CONST);
}

inline void
Set_BE_ST_unknown_const(const ST_IDX idx)
{
  Be_symbol_table[idx].Set_flag(BE_ST_UNKNOWN_CONST);
}

inline void
Set_BE_ST_unknown_const(BE_ST *const be_st)
{
  be_st->Set_flag(BE_ST_UNKNOWN_CONST);
}

inline void
Set_BE_ST_unknown_const(const ST *const st)
{
  Be_symbol_table[ST_st_idx(st)].Set_flag(BE_ST_UNKNOWN_CONST);
}

inline void
Clear_BE_ST_unknown_const(BE_ST *const be_st)
{
  be_st->Clear_flag(BE_ST_UNKNOWN_CONST);
}

inline void
Clear_BE_ST_unknown_const(const ST *const st)
{
  Be_symbol_table[ST_st_idx(st)].Clear_flag(BE_ST_UNKNOWN_CONST);
}

inline void
Clear_BE_ST_unknown_const(const ST_IDX idx)
{
  Be_symbol_table[idx].Clear_flag(BE_ST_UNKNOWN_CONST);
}


inline BOOL
BE_ST_pu_has_valid_addr_flags(const ST_IDX idx)
{
  return Be_symbol_table[idx].Is_set(BE_ST_PU_HAS_VALID_ADDR_FLAGS);
}

inline BOOL
BE_ST_pu_has_valid_addr_flags(const BE_ST *const be_st)
{
  return be_st->Is_set(BE_ST_PU_HAS_VALID_ADDR_FLAGS);
}

inline BOOL
BE_ST_pu_has_valid_addr_flags(const ST *const st)
{
  return Be_symbol_table[ST_st_idx(st)].Is_set(BE_ST_PU_HAS_VALID_ADDR_FLAGS);
}

inline void
Set_BE_ST_pu_has_valid_addr_flags(const ST_IDX idx)
{
  Be_symbol_table[idx].Set_flag(BE_ST_PU_HAS_VALID_ADDR_FLAGS);
}

inline void
Set_BE_ST_pu_has_valid_addr_flags(BE_ST *const be_st)
{
  be_st->Set_flag(BE_ST_PU_HAS_VALID_ADDR_FLAGS);
}

inline void
Set_BE_ST_pu_has_valid_addr_flags(const ST *const st)
{
  Be_symbol_table[ST_st_idx(st)].Set_flag(BE_ST_PU_HAS_VALID_ADDR_FLAGS);
}

inline void
Clear_BE_ST_pu_has_valid_addr_flags(BE_ST *const be_st)
{
  be_st->Clear_flag(BE_ST_PU_HAS_VALID_ADDR_FLAGS);
}

inline void
Clear_BE_ST_pu_has_valid_addr_flags(const ST *const st)
{
  Be_symbol_table[ST_st_idx(st)].Clear_flag(BE_ST_PU_HAS_VALID_ADDR_FLAGS);
}

inline void
Clear_BE_ST_pu_has_valid_addr_flags(const ST_IDX idx)
{
  Be_symbol_table[idx].Clear_flag(BE_ST_PU_HAS_VALID_ADDR_FLAGS);
}


inline BOOL
BE_ST_pu_needs_addr_flag_adjust(const ST_IDX idx)
{
  return Be_symbol_table[idx].Is_set(BE_ST_PU_NEEDS_ADDR_FLAG_ADJUST);
}

inline BOOL
BE_ST_pu_needs_addr_flag_adjust(const BE_ST *const be_st)
{
  return be_st->Is_set(BE_ST_PU_NEEDS_ADDR_FLAG_ADJUST);
}

inline BOOL
BE_ST_pu_needs_addr_flag_adjust(const ST *const st)
{
  return Be_symbol_table[ST_st_idx(st)].Is_set(BE_ST_PU_NEEDS_ADDR_FLAG_ADJUST);
}

inline void
Set_BE_ST_pu_needs_addr_flag_adjust(const ST_IDX idx)
{
  Be_symbol_table[idx].Set_flag(BE_ST_PU_NEEDS_ADDR_FLAG_ADJUST);
}

inline void
Set_BE_ST_pu_needs_addr_flag_adjust(BE_ST *const be_st)
{
  be_st->Set_flag(BE_ST_PU_NEEDS_ADDR_FLAG_ADJUST);
}

inline void
Set_BE_ST_pu_needs_addr_flag_adjust(const ST *const st)
{
  Be_symbol_table[ST_st_idx(st)].Set_flag(BE_ST_PU_NEEDS_ADDR_FLAG_ADJUST);
}

inline void
Clear_BE_ST_pu_needs_addr_flag_adjust(BE_ST *const be_st)
{
  be_st->Clear_flag(BE_ST_PU_NEEDS_ADDR_FLAG_ADJUST);
}

inline void
Clear_BE_ST_pu_needs_addr_flag_adjust(const ST *const st)
{
  Be_symbol_table[ST_st_idx(st)].Clear_flag(BE_ST_PU_NEEDS_ADDR_FLAG_ADJUST);
}

inline void
Clear_BE_ST_pu_needs_addr_flag_adjust(const ST_IDX idx)
{
  Be_symbol_table[idx].Clear_flag(BE_ST_PU_NEEDS_ADDR_FLAG_ADJUST);
}




//
// BE-ST related utilities
//

// Return TRUE iff the ST is known to be a constant initialized to
// some value.
extern BOOL
ST_is_const_initialized(const ST *);

// Return TRUE iff the ST is known to be a constant scalar initialized
// to a value we can determine at compile time and return in the
// argument tcon_copy.
extern BOOL
ST_is_const_initialized_scalar(const ST *, TCON &tcon_copy);

// Return the INITV_IDX of the value of the ST if the ST is a const
// initialized scalar and we can find the INITV.
extern INITV_IDX
ST_is_const_and_has_initv(const ST *);

// Return the INITV_IDX of the value of the ST if st is a
// initialized scalar and we can find the INITV.
extern INITV_IDX
ST_has_initv(const ST *);


// Back-end-specific information about each PU

class BE_PU {
private:
  mUINT16 last_label;
public:
  INT16 Last_label(void) const { return last_label; }
};

class BE_PREG {
private:
  WN *home_location;
public:
  BE_PREG(void) : home_location(NULL)   { }
  void  Set_home_location(WN *wn)       { home_location = wn; }
  WN   *Home_location(void) const       { return home_location; }
};

typedef RELATED_SEGMENTED_ARRAY<BE_PREG> BE_PREG_TAB;

extern BE_PREG_TAB Be_preg_tab;

// Create_Preg for back end components that want to associate a
// home location with each register.

static inline PREG_NUM
Create_Preg(TYPE_ID mtype, char *name, WN *home)
{
  PREG_NUM retval = Create_Preg(mtype, name);
  Be_preg_tab[retval - Last_Dedicated_Preg_Offset].Set_home_location(home);
  return retval;
}

static inline WN *
Preg_Home(PREG_NUM preg)
{
  const UINT idx = preg - Last_Dedicated_Preg_Offset;
  return (idx < Be_preg_tab.Size()) ? Be_preg_tab[idx].Home_location() : NULL;
}

extern void BE_symtab_initialize_be_scopes(void);
extern void BE_symtab_free_be_scopes(void);
extern void BE_symtab_alloc_scope_level(const SYMTAB_IDX);


#endif // be_symtab_INCLUDED
